package com.zhanhong.opencvdemo.presenter;

import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.CursorLoader;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.content.FileProvider;
import android.text.TextUtils;
import android.util.Log;

import com.zhanhong.opencvdemo.config.AnswerSheetConfig;
import com.zhanhong.opencvdemo.model.AnswerSheetModel;
import com.zhanhong.opencvdemo.model.AnswerSheetModel.AnswerRowModel;
import com.zhanhong.opencvdemo.model.AnswerSheetModel.AnswerSheetItemModel;
import com.zhanhong.opencvdemo.utils.ThreadUtils;
import com.zhanhong.opencvdemo.view.CropActivity;
import com.zhanhong.opencvdemo.view.MainActivity;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.InstallCallbackInterface;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfDouble;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;

import java.io.File;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

public class MainPresenterImpl implements MainPresenter {

    private static final String TAG = "MainPresenter";
    private LoaderCallbackInterface mLoaderCallback;
    //是否需要裁剪
    private boolean NEED_CROP = false;
    private final int GALLERY_REQUEST_CODE = 1;//图库
    private final int CAMERA_REQUEST_CODE = 2;//相机
    private final int CROP_REQUEST_CODE = 3;//裁切
    private final int ADVANCE_CROP_REQUEST_CODE = 4;//高级裁切（裁剪答题区域）
    private final MainActivity mActivity;
    private File mTempFileDir = new File(Environment.getExternalStorageDirectory().getPath() + "/opencvdemo/cache");
    private File mTempFile;
    private File mCorpFile;
    private String mPhotoFileName;
    private String mCropImgPath;

    public MainPresenterImpl(MainActivity activity) {
        mActivity = activity;
    }

    @Override
    public void initOpenCV() {
        mLoaderCallback = new BaseLoaderCallback(mActivity.getApplicationContext()) {
            @Override
            public void onManagerConnected(int status) {
                switch (status) {
                    case LoaderCallbackInterface.SUCCESS: {
                        Log.e(TAG, "OpenCV loaded successfully");
                    }
                    break;
                    default: {
                        super.onManagerConnected(status);
                    }
                    break;
                }
            }

            @Override
            public void onPackageInstall(int operation, InstallCallbackInterface callback) {

            }
        };
        if (!OpenCVLoader.initDebug()) {
            Log.e(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION, mActivity.getApplicationContext(), mLoaderCallback);
        } else {
            Log.e(TAG, "OpenCV library found inside package. Using it!");
            mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
        }
    }

    @Override
    public void handleActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case GALLERY_REQUEST_CODE:
                if (data != null) {
                    Uri uri = data.getData();
                    if (uri != null) {
                        if (NEED_CROP) {
                            crop(uri);
                        } else {
                            String path = getPicPathInGallery(uri);
                            if (TextUtils.isEmpty(path)) {
                                mTempFile = null;
                            } else {
                                mTempFile = new File(path);
                                mActivity.onPhotoGet(mTempFile);
                            }
                        }
                    }
                }
                break;
            case CAMERA_REQUEST_CODE:
                if (hasSdcard()) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        mTempFile = new File(Environment.getExternalStorageDirectory(), mPhotoFileName);
                        if (mTempFile.exists() && mTempFile.length() > 0) {
                            if (NEED_CROP) {
                                crop(getImageContentUri(mActivity, mTempFile));
                            } else {
                                mActivity.onPhotoGet(mTempFile);
                            }
                        }
                    } else {
                        mTempFile = new File(Environment.getExternalStorageDirectory(), mPhotoFileName);
                        if (mTempFile.exists() && mTempFile.length() > 0) {
                            if (NEED_CROP) {
                                crop(Uri.fromFile(mTempFile));
                            } else {
                                mActivity.onPhotoGet(mTempFile);
                            }
                        }
                    }
                }
                break;
            case CROP_REQUEST_CODE:
                if (resultCode == Activity.RESULT_OK) {
                    File file = new File(mCropImgPath);
                    mActivity.onPhotoGet(file);
                }
                break;
            case ADVANCE_CROP_REQUEST_CODE:
                if (resultCode == Activity.RESULT_OK && data != null) {
                    String cropPath = data.getStringExtra("cropPath");
                    mActivity.onPhotoCrop(new File(cropPath), "原图");
                }
                break;
        }
    }

    @Override
    public void takePhoto() {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (intent.resolveActivity(mActivity.getPackageManager()) != null) {
            File photoFile = null;
            try {
                photoFile = createImageFile();
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (photoFile != null) {
                Uri photoURI = FileProvider.getUriForFile(mActivity, "com.zhanhong.fileprovider", photoFile);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                mActivity.startActivityForResult(intent, CAMERA_REQUEST_CODE);
            }
        }
    }

    @Override
    public void viewAlbum() {
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");
        mActivity.startActivityForResult(intent, GALLERY_REQUEST_CODE);
    }

    @Override
    public void cropPhoto(File file) {
        Intent intent = new Intent(mActivity, CropActivity.class);
        intent.putExtra("filePath", file.getAbsolutePath());
        mActivity.startActivityForResult(intent, ADVANCE_CROP_REQUEST_CODE);
    }

    @Override
    public void dealWithPhoto(final File file) {
        //总步骤数
        final int total = 5;

        ThreadUtils.runOnSubThread(new Runnable() {
            @Override
            public void run() {
                Bitmap srcBitmap = BitmapFactory.decodeFile(file.getAbsolutePath());

                if (srcBitmap == null) {
                    return;
                }

                Mat srcMat = new Mat();
                Utils.bitmapToMat(srcBitmap, srcMat);

                AnswerSheetModel answerSheet = new AnswerSheetModel(srcMat.width(), srcMat.height());

                //1灰度化
                Mat grayMat = doGray(srcBitmap, srcMat, 1, total);

                //2模糊降噪
                Mat blurMat = doBlur(srcBitmap, grayMat, 2, total);

                //3二值化
                Mat binaryMat = doBinary(srcBitmap, blurMat, 3, total);

                //4绘制参考线
                Mat measureMat = doMeasure(srcBitmap, binaryMat, answerSheet, 4, total);

                //5识别填涂位置
                checkAnswer(measureMat, answerSheet, 5, total);

                srcMat.release();
                grayMat.release();
                blurMat.release();
                binaryMat.release();
                measureMat.release();
            }
        });
    }

    private void checkAnswer(Mat preMat, AnswerSheetModel answerSheet, int current, int total) {
        final String stepName = "识别填涂位置";
        stepDealStart(current, total, stepName);
        try {
            for (int i = 0; i < answerSheet.answerRows.size(); i++) {
                AnswerRowModel answerRow = answerSheet.answerRows.get(i);
                for (int j = 0; j < answerRow.answers.size(); j++) {
                    AnswerSheetItemModel answerItem = answerRow.answers.get(j);
                    for (int k = 0; k < answerItem.points.length; k++) {
                        if (k % 2 == 0 && k < answerItem.points.length - 1) {
                            Point tlPoint = answerItem.points[k];
                            Point brPoint = answerItem.points[k + 1];
                            float offsetX = answerSheet.answerWidth * AnswerSheetConfig.OPTION_SHRINK_FACTOR;
                            float offsetY = answerSheet.answerHeight * AnswerSheetConfig.OPTION_SHRINK_FACTOR;
                            Point targetTlPoint = new Point(tlPoint.x + offsetX, tlPoint.y + offsetY);
                            Point targetBrPoint = new Point(brPoint.x - offsetX, brPoint.y - offsetY);
                            Mat roiMat = preMat.submat(new Rect(targetTlPoint, targetBrPoint));
                            MatOfDouble meanMat = new MatOfDouble();
                            MatOfDouble stdDevMat = new MatOfDouble();
                            double[] mean = new double[1];
                            double[] stdDev = new double[1];
                            Core.meanStdDev(roiMat, meanMat, stdDevMat);
                            meanMat.get(0, 0, mean);
                            stdDevMat.get(0, 0, stdDev);
                            float factor = formatDouble(mean[0]);
                            switch (k / 2) {
                                case 0:
                                    answerItem.factorA = factor;
                                    break;
                                case 1:
                                    answerItem.factorB = factor;
                                    break;
                                case 2:
                                    answerItem.factorC = factor;
                                    break;
                                case 3:
                                    answerItem.factorD = factor;
                                    break;
                            }
                            meanMat.release();
                            stdDevMat.release();
                            roiMat.release();
                        }
                    }
                }
            }
            List<AnswerSheetItemModel> answers = new ArrayList<>();
            List<Float> factors = new ArrayList<>();
            for (AnswerRowModel answerRow : answerSheet.answerRows) {
                for (AnswerSheetItemModel answer : answerRow.answers) {
                    factors.add(answer.factorA);
                    factors.add(answer.factorB);
                    factors.add(answer.factorC);
                    factors.add(answer.factorD);
                }
            }
            Collections.sort(factors);
            float maxFactor = factors.get(factors.size() - 1) > 255F * AnswerSheetConfig.LIMIT_ACCEPT_MAX_FACTOR ? 255F * AnswerSheetConfig.LIMIT_ACCEPT_MAX_FACTOR : factors.get(factors.size() - 1);
            float minFactor = factors.get(0);
            float limitMaxFactor = maxFactor * AnswerSheetConfig.LIMIT_ACCEPT_MAX_FACTOR;
            boolean limitMaxFactorIsValid = (maxFactor - minFactor) > 255F * AnswerSheetConfig.LIMIT_ACCEPT_MIN_FACTOR;
            for (AnswerRowModel answerRow : answerSheet.answerRows) {
                for (AnswerSheetItemModel answer : answerRow.answers) {
                    answer.checkA = answer.factorA > limitMaxFactor && limitMaxFactorIsValid;
                    answer.checkB = answer.factorB > limitMaxFactor && limitMaxFactorIsValid;
                    answer.checkC = answer.factorC > limitMaxFactor && limitMaxFactorIsValid;
                    answer.checkD = answer.factorD > limitMaxFactor && limitMaxFactorIsValid;
                    if (!answer.checkA && !answer.checkB && !answer.checkC && !answer.checkD) {
                        float totalFactors = answer.factorA + answer.factorB + answer.factorC + answer.factorD;
                        answer.checkA = answer.factorA > totalFactors * AnswerSheetConfig.LIMIT_ACCEPT_TOTAL_PERCENT_FACTOR && answer.factorA > maxFactor * AnswerSheetConfig.LIMIT_RECHECK_MIN_FACTOR && limitMaxFactorIsValid;
                        answer.checkB = answer.factorB > totalFactors * AnswerSheetConfig.LIMIT_ACCEPT_TOTAL_PERCENT_FACTOR && answer.factorB > maxFactor * AnswerSheetConfig.LIMIT_RECHECK_MIN_FACTOR && limitMaxFactorIsValid;
                        answer.checkC = answer.factorC > totalFactors * AnswerSheetConfig.LIMIT_ACCEPT_TOTAL_PERCENT_FACTOR && answer.factorC > maxFactor * AnswerSheetConfig.LIMIT_RECHECK_MIN_FACTOR && limitMaxFactorIsValid;
                        answer.checkD = answer.factorD > totalFactors * AnswerSheetConfig.LIMIT_ACCEPT_TOTAL_PERCENT_FACTOR && answer.factorD > maxFactor * AnswerSheetConfig.LIMIT_RECHECK_MIN_FACTOR && limitMaxFactorIsValid;
                    }
                    answers.add(answer);
                }
            }
            stepDealComplete(current, total, stepName, null, answers, true);
        } catch (Exception e) {
            stepDealComplete(current, current, stepName + "失败：" + e.getMessage(), null, null, false);
        }
    }

    @NonNull
    private Mat doMeasure(Bitmap srcBitmap, Mat preMat, AnswerSheetModel answerSheet, int current, int total) {
        final String stepName = "内容分析";
        stepDealStart(current, total, stepName);
        final Bitmap measureBitmap = createBitmapAsSrc(srcBitmap);
        Mat measureMat = preMat.clone();
        try {
            calcReferenceAxis(measureMat, answerSheet);
            Utils.matToBitmap(measureMat, measureBitmap);
            stepDealComplete(current, total, stepName, measureBitmap, null, true);
        } catch (Exception e) {
            measureMat.release();
            stepDealComplete(current, current, stepName + "失败：" + e.getMessage(), null, null, false);
        }
        return measureMat;
    }

    @NonNull
    private Mat doBinary(Bitmap srcBitmap, Mat preMat, final int current, final int total) {
        final String stepName = "二值化";
        stepDealStart(current, total, stepName);
        final Bitmap binaryBitmap = createBitmapAsSrc(srcBitmap);
        Mat binaryMat = new Mat();
        try {
            Imgproc.adaptiveThreshold(preMat, binaryMat, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, 225, 40);
            Utils.matToBitmap(binaryMat, binaryBitmap);
            stepDealComplete(current, total, stepName, binaryBitmap, null, true);
        } catch (Exception e) {
            binaryMat.release();
            stepDealComplete(current, current, stepName + "失败：" + e.getMessage(), null, null, false);
        }
        return binaryMat;
    }

    @NonNull
    private Mat doBlur(Bitmap srcBitmap, Mat preMat, final int current, final int total) {
        final String stepName = "高斯模糊降噪";
        stepDealStart(current, total, stepName);
        final Bitmap blurBitmap = createBitmapAsSrc(srcBitmap);
        Mat blurMat = new Mat();
        try {
            Imgproc.GaussianBlur(preMat, blurMat, new Size(3, 3), 0);
            Utils.matToBitmap(blurMat, blurBitmap);
            stepDealComplete(current, total, stepName, blurBitmap, null, true);
        } catch (Exception e) {
            blurMat.release();
            stepDealComplete(current, current, stepName + "失败：" + e.getMessage(), null, null, false);
        }
        return blurMat;
    }

    @NonNull
    private Mat doGray(Bitmap srcBitmap, Mat preMat, final int current, final int total) {
        final String stepName = "灰度化";
        stepDealStart(current, total, stepName);
        final Bitmap grayBitmap = createBitmapAsSrc(srcBitmap);
        Mat grayMat = new Mat();
        try {
            Imgproc.cvtColor(preMat, grayMat, Imgproc.COLOR_BGRA2GRAY);
            Utils.matToBitmap(grayMat, grayBitmap);
            stepDealComplete(current, total, stepName, grayBitmap, null, true);
        } catch (Exception e) {
            grayMat.release();
            stepDealComplete(current, current, stepName + "失败：" + e.getMessage(), null, null, false);
        }
        return grayMat;
    }

    private void calcReferenceAxis(Mat measureMat, AnswerSheetModel answerSheet) {
        //绘制横向直线
        Imgproc.line(measureMat, new Point(0, answerSheet.offsetTop), new Point(answerSheet.width, answerSheet.offsetTop), getLineColorWhite());
        Imgproc.line(measureMat, new Point(0, answerSheet.height - answerSheet.offsetBottom), new Point(answerSheet.width, answerSheet.height - answerSheet.offsetBottom), getLineColorWhite());
        for (int i = 1; i <= AnswerSheetConfig.TOTAL_ROW_COUNT; i++) {
            int preEmptyRowCount = i / AnswerSheetConfig.PER_ROW_COUNT;
            float marginTop = answerSheet.offsetTop + i * answerSheet.answerHeight + preEmptyRowCount * answerSheet.emptyRowHeight;
            //最后一条线不需要在循环中绘制，之前已经绘制过
            if (i < AnswerSheetConfig.TOTAL_ROW_COUNT) {
                if (i % AnswerSheetConfig.PER_ROW_COUNT == 0) {
                    Imgproc.line(measureMat, new Point(0, marginTop - answerSheet.emptyRowHeight), new Point(answerSheet.width, marginTop - answerSheet.emptyRowHeight), getLineColorWhite());
                }
                Imgproc.line(measureMat, new Point(0, marginTop), new Point(answerSheet.width, marginTop), getLineColorWhite());
            }
        }
        //绘制纵向直线
        Imgproc.line(measureMat, new Point(answerSheet.offsetLeft, 0), new Point(answerSheet.offsetLeft, answerSheet.height), getLineColorWhite());
        Imgproc.line(measureMat, new Point(answerSheet.width - answerSheet.offsetRight, 0), new Point(answerSheet.width - answerSheet.offsetRight, answerSheet.height), getLineColorWhite());
        for (int i = 1; i <= AnswerSheetConfig.TOTAL_COL_COUNT; i++) {
            int preEmptyColCount = i / AnswerSheetConfig.PER_COL_COUNT;
            float marginLeft = answerSheet.offsetLeft + i * answerSheet.answerWidth + preEmptyColCount * answerSheet.emptyColWidth;

            //最后一条线不需要在循环中绘制，之前已经绘制过
            if (i < AnswerSheetConfig.TOTAL_COL_COUNT) {
                if (i % AnswerSheetConfig.PER_COL_COUNT == 0) {
                    Imgproc.line(measureMat, new Point(marginLeft - answerSheet.emptyColWidth, 0), new Point(marginLeft - answerSheet.emptyColWidth, answerSheet.height), getLineColorWhite());
                }
                Imgproc.line(measureMat, new Point(marginLeft, 0), new Point(marginLeft, answerSheet.height), getLineColorWhite());
            }
        }
    }

    public float formatDouble(double value) {
        return (float) Math.round(value * 100) / 100;
    }

    @NonNull
    private Scalar getLineColorWhite() {
        return new Scalar(255, 255, 255);
    }

    private Bitmap createBitmapAsSrc(Bitmap srcBitmap) {
        return Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
    }

    private void stepDealComplete(final int current, final int total, final String stepName, final Bitmap resultBitmap, final List<AnswerSheetItemModel> answers, final boolean success) {
        ThreadUtils.runOnUIThread(new Runnable() {
            @Override
            public void run() {
                mActivity.onPhotoDealComplete(resultBitmap, answers, stepName, current, total, success);
            }
        });
    }

    private void stepDealStart(final int current, final int total, final String stepName) {
        ThreadUtils.runOnUIThread(new Runnable() {
            @Override
            public void run() {
                mActivity.onPhotoDealStart(stepName, current, total);
            }
        });
    }

    private File createImageFile() {
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(new java.util.Date());
        String imageFileName = "IMG_" + timeStamp;
        File image = new File(Environment.getExternalStorageDirectory() + File.separator + imageFileName + ".png");
        mPhotoFileName = image.getAbsolutePath().substring(image.getAbsolutePath().lastIndexOf("/") + 1);
        return image;
    }

    private void crop(Uri uri) {
        if (!mTempFileDir.exists()) {
            mTempFileDir.mkdirs();
        }
        mCorpFile = new File(mTempFileDir, getPhotoFileName());
        //裁剪图片意图
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("scale", true);//黑边
        intent.putExtra("scaleUpIfNeeded", true);//黑边

        //裁剪框的比例
        //intent.putExtra("aspectX", 3);
        //intent.putExtra("aspectY", 4);
        //裁剪后输出图片的尺寸大小
        //intent.putExtra("outputX", 400);
        //intent.putExtra("outputY", 400);
        //图片格式
        intent.putExtra("outputFormat", "PNG");
        intent.putExtra("noFaceDetection", true);// 取消人脸识别
        intent.putExtra("return-data", false);// true:不返回uri，false：返回uri
        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mCorpFile));
        mCropImgPath = mCorpFile.getAbsolutePath();
        mActivity.startActivityForResult(intent, CROP_REQUEST_CODE);
    }

    private String getPhotoFileName() {
        Date date = new Date(System.currentTimeMillis());
        SimpleDateFormat dateFormat = new SimpleDateFormat("'IMG'_yyyyMMddHHmmss");
        return dateFormat.format(date) + ".png";
    }

    private boolean hasSdcard() {
        return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
    }

    private static Uri getImageContentUri(Context context, File imageFile) {
        String filePath = imageFile.getAbsolutePath();
        Cursor cursor = context.getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                new String[]{MediaStore.Images.Media._ID},
                MediaStore.Images.Media.DATA + "=? ",
                new String[]{filePath}, null);
        if (cursor != null && cursor.moveToFirst()) {
            int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
            Uri baseUri = Uri.parse("content://media/external/images/media");
            cursor.close();
            return Uri.withAppendedPath(baseUri, "" + id);
        } else {
            if (imageFile.exists()) {
                ContentValues values = new ContentValues();
                values.put(MediaStore.Images.Media.DATA, filePath);
                if (cursor != null) {
                    cursor.close();
                }
                return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
            } else {
                if (cursor != null) {
                    cursor.close();
                }
                return null;
            }
        }
    }

    private String getPicPathInGallery(Uri uri) {
        String path = "";
        if (!TextUtils.isEmpty(uri.getAuthority())) {
            // Android多媒体数据库的封装接口，具体的看Android文档
            Cursor cursor;
            CursorLoader cursorLoader = new CursorLoader(mActivity, uri, null, null, null, null);
            cursor = cursorLoader.loadInBackground();
            if (cursor != null) {
                //获得用户选择的图片的索引值
                int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                //将光标移至开头，这个很重要，不小心很容易引起越界
                cursor.moveToFirst();
                //最后根据索引值获取图片路径
                path = cursor.getString(column_index);
            }
        } else {
            path = uri.getPath();
        }
        return path;
    }

}

//4圆检测
//List<CircleModel> circleModels = new ArrayList<>();
//Mat circleCheckMat = doCircleCheck(srcBitmap, blurMat, circleModels, 3, total);

/*private Mat doCircleCheck(Bitmap srcBitmap, Mat srcMat, List<CircleModel> circleModels, int current, int total) {
    final String stepName = "圆标记检测";
    photoDealStart(current, total, stepName);
    final Bitmap circleCheckBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
    Mat circleCheckMat = new Mat();
    Mat circleResultMat = new Mat();
    Utils.bitmapToMat(srcBitmap, circleResultMat);
    try {
        Imgproc.HoughCircles(srcMat, circleCheckMat, Imgproc.HOUGH_GRADIENT, 2, 10, 150, 50, 5, 100);
        int circleCount = circleCheckMat.cols();
        *//*if (circleCount == 4) {*//*
        for (int i = 0; i < circleCount; i++) {
            float[] circleInfo = new float[3];
            circleCheckMat.get(0, i, circleInfo);
            circleModels.add(new CircleModel(circleInfo[0], circleInfo[1], circleInfo[2]));
            Imgproc.circle(circleResultMat, new Point(circleInfo[0], circleInfo[1]), (int) circleInfo[2], new Scalar(0, 0, 255), 2, 8, 0);
        }
        Utils.matToBitmap(circleResultMat, circleCheckBitmap);
        photoDealComplete(current, total, stepName, circleCheckBitmap, true);
        *//*} else {
            throw new RuntimeException("未检测到有效圆标记，请使用有效且清晰的答题卡图片");
        }*//*
    } catch (Exception e) {
        circleCheckMat.release();
        circleResultMat.release();
        photoDealComplete(current, current, "圆标记检测失败：" + e.getMessage(), null, false);
    } finally {
        srcMat.release();
    }
    return circleResultMat;
}*/


//4轮廓分析
//Mat edgeMat = doEdge(srcBitmap, binaryMat, srcMat, answerSheet, 4, total);

/*private Mat doEdge(Bitmap srcBitmap, Mat preMat, Mat srcMat, AnswerSheetModel answerSheet, int current, int total) {
    final String stepName = "轮廓分析";
    photoDealStart(current, total, stepName);
    final Bitmap edgeBitmap = createBitmapAsSrc(srcBitmap);
    Mat edgeMat = srcMat.clone();
    Mat hierarchyMat = new Mat();
    List<MatOfPoint> edgePoints = new ArrayList<>();
    try {
        Imgproc.findContours(preMat, edgePoints, hierarchyMat, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
        for (int i = 0; i < edgePoints.size(); i++) {
            Scalar scalar = getLineColorBlue();
            MatOfPoint matOfPoint = edgePoints.get(i);
            double contourArea = Imgproc.contourArea(matOfPoint);
            float answerArea = answerSheet.answerWidth * answerSheet.answerHeight;
            if (contourArea >= answerArea / 2 && contourArea <= answerArea) {
                String areaStr = new BigDecimal(contourArea).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
                int[] point = new int[2];
                matOfPoint.get(0, 0, point);
                MatOfPoint2f curve = new MatOfPoint2f(matOfPoint.toArray());
                MatOfPoint2f approxCurve = new MatOfPoint2f();
                Imgproc.approxPolyDP(curve, approxCurve, 10, true);
                if (approxCurve.rows() == 4) {
                    Imgproc.putText(edgeMat, areaStr, new Point(point[0], point[1]), Core.FONT_HERSHEY_PLAIN, 1, scalar);
                    Imgproc.drawContours(edgeMat, edgePoints, i, scalar, 2);
                }
            }
        }
        Utils.matToBitmap(edgeMat, edgeBitmap);
        photoDealComplete(current, total, stepName, edgeBitmap, true);
    } catch (Exception e) {
        edgeMat.release();
        photoDealComplete(current, current, "轮廓分析失败：" + e.getMessage(), null, false);
    } finally {
        hierarchyMat.release();
    }
    return edgeMat;
}*/